﻿using System;
using System.Collections.Generic;
using System.Linq;
using HK.Core.Common.Protocol;
using HK.Core.Common.Protocol.Data;
using HK.Core.Extend;
using HK.Core.Serializable.Attribute;
using HK.Core.Utils;
using UnityEngine;

namespace HK.Core.Common.Data
{
    /// <summary>
    /// Json数据
    /// </summary>
    [Serializable]
    public abstract class JsonData : DataBase, IJsonData
    {
        /// <summary>
        /// 初始化.
        /// </summary>
        public virtual void Init() {}

        /// <summary>
        /// 重置.
        /// </summary>
        public virtual void Reset()
        {
            // 清空
            Clear();
            // 初始化
            Init();
        }

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public virtual bool ApplyData(IJsonData iData, bool iImport = false)
        {
            Dirty = false;
            return Dirty;
        }

#region Update

        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        protected byte UpdateValue(byte iCurValue, byte iDstValue, bool iImport)
        {
            var dirty = iCurValue != iDstValue;
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }        
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        protected int UpdateValue(int iCurValue, int iDstValue, bool iImport)
        {
            var dirty = iCurValue != iDstValue;
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }    
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        protected uint UpdateValue(uint iCurValue, uint iDstValue, bool iImport)
        {
            var dirty = iCurValue != iDstValue;
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        protected long UpdateValue(long iCurValue, long iDstValue, bool iImport)
        {
            var dirty = iCurValue != iDstValue;
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        protected float UpdateValue(float iCurValue, float iDstValue, bool iImport)
        {
            var dirty = Math.Abs(iCurValue - iDstValue) > Mathf.Epsilon;
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        protected double UpdateValue(double iCurValue, double iDstValue, bool iImport)
        {
            var dirty = Math.Abs(iCurValue - iDstValue) > Mathf.Epsilon;
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        protected bool UpdateValue(bool iCurValue, bool iDstValue, bool iImport)
        {
            var dirty = iCurValue != iDstValue;
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        protected string UpdateValue(string iCurValue, string iDstValue, bool iImport)
        {
            var dirty = UtilsString.Diff(iCurValue, iDstValue);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        protected List<string> UpdateValue(List<string> iCurValue, List<string> iDstValue, bool iImport)
        {
            var dirty = UtilsArray.Diff(iCurValue, iDstValue);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        protected List<TElement> UpdateValue<TElement>(List<TElement> iCurValue, List<TElement> iDstValue, bool iImport)
            where TElement : JsonData, IEquatable<TElement>
        {
            var dirty = UtilsArray.Diff(iCurValue, iDstValue);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        protected Color UpdateValue(Color iCurValue, Color iDstValue, bool iImport)
        {
            var dirty = !ColorEx.IsSameColor(iCurValue, iDstValue);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        } 
        
#endregion
        
        /// <summary>
        /// 当前对象的字符串化文字
        /// <para>* Json格式</para>
        /// </summary>
        /// <returns>字符串化文字</returns>
        public abstract override string ToString();
        
    }

    /// <summary>
    /// Json数据
    /// </summary>
    /// <typeparam name="TJson">Json数据类型</typeparam>
    [Serializable]
    public class JsonData<TJson> : JsonData where TJson : JsonData
    {
        /// <summary>
        /// Json对象的字符串
        /// </summary>
        /// <returns>Json字符串</returns>
        public override string ToString()
        {
            return UtilsJson<JsonData<TJson>>.ConvertToJsonString(this);
        }
    }

    /// <summary>
    /// Json列表数据
    /// </summary>
    /// <typeparam name="TList">列表类型</typeparam>
    /// <typeparam name="TElement">列表Element类型</typeparam>
    [Serializable]
    public abstract class ListJsonData<TList, TElement> : JsonData<TList>, IListJsonData<TElement>
        where TList : JsonData, IListJsonData<TElement>
        where TElement : JsonData, IListElement, IEquatable<TElement>
    {
        [SerializeField]
        protected List<TElement> list = new List<TElement>();
        /// <summary>
        /// 列表
        /// </summary>
        public List<TElement> List => list;

        /// <summary>
        /// 服务器器数
        /// </summary>
        public int Count => list.Count;
        
        /// <summary>
        /// 唯一标志位
        /// <para>* true : 不允许有重复元素出现; false : 反之;</para>
        /// </summary>
        public virtual bool Distinct => true;

        /// <summary>
        /// 存在校验
        /// </summary>
        /// <param name="iKey">Key</param>
        /// <param name="oTarget"></param>
        /// <returns></returns>
        public virtual bool Exist(string iKey, out TElement oTarget)
        {
            oTarget = default(TElement);
            if (string.IsNullOrEmpty(iKey) || 0 >= Count) return false;

            var count = Count;
            for (var idx = 0; idx < count; ++idx)
            {
                var loop = list[idx];
                if(null == loop || !loop.Valid || !iKey.Equals(loop.Key)) continue;

                oTarget = loop;
                break;
            }

            var flg = default(TElement) != oTarget && !oTarget.Valid;
            if (!flg)
            {
                oTarget = default(TElement);
            }
            return flg;
        }

        /// <summary>
        /// 追加
        /// </summary>
        /// <param name="iElement">Element</param>
        public virtual void AddElement(TElement iElement)
        {
            if(default(TElement) == iElement || !iElement.Valid) return;

            if (Distinct)
            {
                if(list.Exists(iO => iO.Equals(iElement))) return;
                list.Add(iElement);
            }
            else
            {
                list.Add(iElement);
            }
        }

        /// <summary>
        /// 追加
        /// </summary>
        /// <param name="iElements">Element列表</param>
        public void AddElements(List<TElement> iElements)
        {
            if(null == iElements || 0 >= iElements.Count) return;

            if (0 >= list.Count)
            {
                list.AddRange(iElements);
            }
            else
            {
                var count = iElements.Count;
                for (var idx = 0; idx < count; ++idx)
                {
                    var element = iElements[idx];
                    if(null == element || !element.Valid) continue;

                    if (Distinct)
                    {
                        if (!Exist(element.Key, out var oTarget))
                        {
                            list.Add(element);
                            continue;
                        }
                        if(null == oTarget || !oTarget.Valid) continue;
                        oTarget.ApplyData(element);
                    }
                    else
                    {
                        list.Add(element);
                    }
                }
            }
        }

        /// <summary>
        /// 排序
        /// </summary>
        /// <param name="iAscending">true:升序; false:降序;</param>
        public void Sort(bool iAscending = true)
        {
            list = iAscending ? list.OrderBy(iO => iO.Key).ToList() : 
                list.OrderByDescending(iO => iO.Key).ToList();
        }
        
        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;

            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is IListJsonData<TElement> listData)
            {
                dirty = UtilsArray.Diff<TElement>(list, listData.List);
                if (dirty)
                {
                    list.Clear();
                    list.AddRange(listData.List);

                    if (!iImport)
                    {
                        Dirty = true;
                    }
                }
            }

            return Dirty;
        }

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();
            
            list.Clear();
        }
    }
}
